package com.lq.learningTest.encapsulation;

/**
 * 超级数组，存储是从序号0开始的
 */
public class SuperArray {

    //维护一个数组,要想什么都存，就要使用顶级父类
    private Integer[] array;
    // 数组存储数据的长度，默认开始是0
    private int size;
    // 数组当前的容量
    private int capacity;

    //判断函数是否成功执行的标准
    private boolean flag = false;

    //构造器之间的调用
    public SuperArray(){
        this(10);
    }
    //构造器的重载
    public SuperArray(int capacity){
        array = new Integer[capacity];
        this.capacity = capacity;
    }

    /**
     * 添加数据的方法,默认是尾插
     * @param data
     */
    public boolean add(Integer data){
        //确保容量足够,如果容量不够就扩容
        ensureCapacity(size + 1);
        array[size++] = data;//这里记住是添加了数据之后再长度自增，因为数组尾部数据的下标比数组长度少一
        flag = true;
        if (flag) {
            flag = false;
            return true;
        }else return false;
    }

    /**
     * 添加数据的方法，指定下标添加
     * @param index
     * @param data
     * @return
     */
    public boolean add(int index,Integer data){
        ensureCapacity(size + 1);
        /**
         * Object src : 原数组
         * int srcPos : 从元数据的起始位置开始
         * Object dest : 目标数组
         * int destPos : 目标数组的开始起始位置
         * int length  : 要copy的数组的长度
         */
        // index以后的数据统一向后移动，空出位置
        System.arraycopy(array, index, array, index + 1,
                size - index);
        array[index] = data;
        size ++;
        flag = true;
        if (flag) {
            flag = false;
            return true;
        }else return false;
    }

    /**
     * 指定下标删除数据，删除成功返回删除的值，否则返回空
     * @param index
     * @return res,null
     */
    public Integer remove(int index) {
        //验证下标是否符合规范
        if(rangeCheck(index)){
            Integer res = array[index];
            /**
             * Object src : 原数组
             * int srcPos : 从元数据的起始位置开始
             * Object dest : 目标数组
             * int destPos : 目标数组的开始起始位置
             * int length  : 要copy的数组的长度
             */
            System.arraycopy(array, index+1, array, index, size-index-1);
            size--;
            return res;
        }
        return null;
    }

    /**
     * 指定下标修改数据
     * @param index
     * @param data
     * @return true,false
     */
    public boolean set(int index,Integer data) {
        //验证下标是否符合规范
        if(rangeCheck(index)){
            array[index] = data;
            return true;
        }
        return false;
    }

    /**
     * 根据下标查询数字,因为查询的数字可以是任何数值又或者是没有，所以这里用int的包装类，因为从基础数据类型到引用数据类型的
     * 转变，所以没查到数据的时候可以返回null,查到数据的时候就返回数值
     * @param index
     * @return array[index],null
     */
    public Integer get(int index){
        if(rangeCheck(index)){
            return array[index];
        }
        return null;
    }

    /**
     * 查看当前有多少个数字
     * @return size
     */
    public int size(){
        return size;
    }


    /**
     * 确保容量，并在需要的时候扩容,这里是执行函数而不是判断函数，因为无论需要的空间与实际的容量大小如何都必须要设置成合适容量
     * 私有方法供类内部使用，对外隐藏
     * @param needCapacity
     */
    private void ensureCapacity(int needCapacity) {
        if (needCapacity > capacity){
            //容量增加了1.5倍
            capacity += (capacity >> 1);
            Integer[] newArray = new Integer[capacity];
            /**
             * Object src : 原数组
             * int srcPos : 从元数据的起始位置开始
             * Object dest : 目标数组
             * int destPos : 目标数组的开始起始位置
             * int length  : 要copy的数组的长度
             */
            System.arraycopy(array, 0, newArray, 0, array.length);
            array = newArray;//旧数组首地址指向新数组首地址，旧数组内容被jvm垃圾回收机制回收
        }
    }

    /**
     * 验证下标是否合法,私有方法供类内部使用，对外隐藏
     * @param index
     * @return
     */
    private boolean rangeCheck(int index) {
        //只要有一个不满足就返回false
        return index <= size-1 && index >= 0;
    }

}


